package com.community.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.community.annotation.SysLog;
import com.community.base.BaseService;
import com.community.common.Const;
import com.community.common.ServerResponse;
import com.community.pojo.*;
import com.community.service.IIntegralService;
import com.community.service.IJedisClientService;
import com.community.service.IQuestionService;
import com.community.service.ISolrService;
import com.community.util.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service("iQuestionService")
public class QuestionServiceImpl extends BaseService implements IQuestionService {

    @Autowired
    private ISolrService iSolrService;

    @Autowired
    private IIntegralService iIntegralService;

    @Autowired
    private IJedisClientService iJedisClientService;

    /**
     * 查询提问
     * @param pageNum 页码
     * @param questionType 问题类型
     * @return
     */
    @SysLog("查询最新提问")
    public ServerResponse<PageInfo> selectByParam(int pageNum,int questionType,HttpServletRequest request){
        Map paramMap = new HashMap();
        //用于获取redis缓存
        String questionSelectType = "";
        if(questionType == Const.QuestionType.NEWQUESTION){//最新
            questionSelectType = Const.QuestionSelectType.NEWQUESTION;
        }else if(questionType == Const.QuestionType.HIGHREWARD){//悬赏
            paramMap.put("offered",Const.YesOrNo.YES);//只查询悬赏
            questionSelectType = Const.QuestionSelectType.HIGHREWARD;
        }else if(questionType == Const.QuestionType.HOT){//热门
            //todo  暂时不提供热门  热门规律暂定
        }else if(questionType == Const.QuestionType.URGENT){//紧急
            questionSelectType = Const.QuestionSelectType.URGENT;
            paramMap.put("emergency_degree",Const.YesOrNo.YES);//是否紧急
        }
        //获取redis缓存
        String redisStr = iJedisClientService.get(questionSelectType);
        if(StringUtil.isNotEmpty(redisStr)){//翻页情况下有缓存直接返回
            List<Map> cacheList =(List<Map>) JSONObject.parse(redisStr);
            //有缓存直接返回
            return ServerResponse.createBySuccess(Const.Msg.SELECTSUCCESS,
                    SearchBigFieldUtil.pageInfo(pageNum,Const.MAXSIZE,cacheList));
        }
        //分页及排序
        PageHelper.startPage(pageNum,Const.MAXSIZETWO,"q.create_time desc");
        //查询
        List<Map> resultList = questionMapper.selectByParamMap(paramMap);
        if(null == resultList){
            return ServerResponse.createByErrorMessage(Const.Msg.SELECTERROR);
        }
        PageInfo pageInfo = new PageInfo(resultList);
        //查询大字段
        ServerResponse<PageInfo> response = SearchBigFieldUtil.selectBigText(pageInfo,Question.ENTITYNAME,
                Const.SolrType.CONTENT,request);
        if(response.isSuccess()){
            List<Map> mapList = response.getData().getList();
            //缓存List
            iJedisClientService.set(questionSelectType,
                    JSONObject.toJSONString(mapList));
            //设置缓存时间
            iJedisClientService.expire(Const.QuestionSelectType.NEWQUESTION,Const.cacheTime*2);//缓存时间2小时
            //返回
            return ServerResponse.createBySuccess(Const.Msg.SELECTSUCCESS,
                    SearchBigFieldUtil.pageInfo(pageNum,Const.MAXSIZE,mapList));
        }
        return ServerResponse.createByErrorMessage(Const.Msg.SELECTERROR);

    }


    /**
     * 新增提问
     * @param paramMap
     * @param request
     * @return
     */
    //todo 参数paramMap 需传入标签名集合 用英文逗号隔开 labelnames
    @Transactional(rollbackFor = { Exception.class })//事物控制
    @SysLog("新增提问")
    public ServerResponse<String> add(Map paramMap,HttpServletRequest request){
        String userName = StringUtil.valueOfString(paramMap.get("userName"));
        if(!LoginUtil.isLogin(request,userName)){//如果登录名与传参登录名不一致
            return ServerResponse.createByErrorMessage(Const.Msg.PARAMTERERROR);
        }
        int offered = NumberUtil.safeToNumber(paramMap.get("offered"));
        double money = NumberUtil.safeToDouble(paramMap.get("money"));
        int emergencyDegree = NumberUtil.safeToNumber(paramMap.get("emergency_degree"));
        if(emergencyDegree == Const.YesOrNo.YES && money < Const.MINMONEY){//如果是紧急并且小于100积分
            return ServerResponse.createByErrorMessage(Const.Msg.PARAMTERERROR);
        }
        if(offered == Const.YesOrNo.YES){
            //如果是悬赏的则进行交易操作
            ServerResponse response = iIntegralService.transaction(PropertiesUtil.getProperty("CapitalAccount"),userName,
                    money,Const.TradingNotes.ONE,Const.TradingNotes.ONE);
            if (!response.isSuccess()){
                return response;
            }
        }
        //新增问题
        Question question = new Question();
        question.setTitle(StringUtil.valueOfString(paramMap.get("title")));//标题
        question.setProposeUser(userName);//提问者
        question.setEmergencyDegree(emergencyDegree);//是否紧急
        question.setOffered(offered);//是否悬赏
        question.setMoney(money);//金额
        question.setAnswerModel(Const.AnswerModel.OPEN);//默认开放，答案可见模式放置答案作者操作，收益归答案作者
        //question.setAnswerModel(NumberUtil.safeToNumber(paramMap.get("answerModel")));//答案可见模式
        //question.setAnswerMoney(NumberUtil.safeToDouble(paramMap.get("answerMoney")));//答案付费金额
        question.setStatus(Const.QuestStatus.WAITANSWER);//问题状态
        if(questionMapper.insert(question) <= 0){//新增
            throw new RuntimeException();
        }
        //新增问题内容（大字段）
        QuestionBigField questionBigField = new QuestionBigField();
        questionBigField.setQid(question.getId());//问题ID
        questionBigField.setBigtext(StringUtil.valueOfString(paramMap.get("content")));//内容
        if(questionBigFieldMapper.insert(questionBigField) <= 0){
            throw new RuntimeException();
        }
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id",UUID.randomUUID());
        doc.addField("joinid",question.getId());
        doc.addField("entityName",Question.ENTITYNAME);//实体名称
        doc.addField("type",Const.SolrType.CONTENT);//实体类型
        doc.addField("title",question.getTitle());//标题
        doc.addField("bigfield",StringUtil.valueOfString(paramMap.get("content")));//大字段内容
        //新增问题标签
        String labels = StringUtil.valueOfString(paramMap.get("labels"));
        if(StringUtil.isNotEmpty(labels)){
            saveLabels(labels,question.getId());
        }
        try {
            iSolrService.add(doc);//添加至solr服务器
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SolrServerException e) {
            e.printStackTrace();
        }
        //添加至缓存
        String questionSelectType = Const.QuestionSelectType.NEWQUESTION;
        //获取redis缓存
        String redisStr = iJedisClientService.get(questionSelectType);
        if(StringUtil.isNotEmpty(redisStr)){//翻页情况下有缓存直接返回
            List<Map> cacheList =(List<Map>) JSONObject.parse(redisStr);
            //更新缓存
            updateRedisCache(cacheList,paramMap,questionSelectType);
        }
        if(question.getOffered() == Const.YesOrNo.YES){
            //如果是悬赏提问
            questionSelectType = Const.QuestionSelectType.HIGHREWARD;
            redisStr = iJedisClientService.get(questionSelectType);
            if(StringUtil.isNotEmpty(redisStr)){//翻页情况下有缓存直接返回
                List<Map> cacheList =(List<Map>) JSONObject.parse(redisStr);
                updateRedisCache(cacheList,paramMap,questionSelectType);
            }
        }

        return ServerResponse.createBySuccessMessage(Const.Msg.SAVESUCCESS);
    }

    /**
     * 搜索对应标题
     * @return
     */
    @SysLog("实时检索标题")
    public ServerResponse<List<Map>> selectTitleByStr(String str){
        List<Map> resultList = Lists.newArrayList();
        try {//设置条件值
            SolrQuery params = new SolrQuery("title:"+str);
            params.setStart(0);
            params.setRows(10);//最多条目数
            //设置显示域
            String[] fields = {"joinid","title"};
            params.setFields(fields);
            //高亮
            params.addHighlightField("title");//高亮值
            params.setHighlight(true);//高亮开关
            params.setHighlightSimplePre("<em class='highlight'>");//前置
            params.setHighlightSimplePost("</em>");//后置
            //查询
            SolrDocumentList solrDocumentList = iSolrService.query(params);
            for (SolrDocument solrDocument : solrDocumentList){
                Map map = new HashMap();
                map.put("joinid",solrDocument.get("joinid"));
                map.put("title",solrDocument.get("title"));
                resultList.add(map);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ServerResponse.createBySuccess(Const.Msg.SELECTSUCCESS,resultList);
    }

    /**
     * 更新问题（一般为修改标题，补充问题，提高悬赏，删除问题）
     * @param paramMap
     * @param request
     * @return
     */
    //todo 参数paramMap 需传入标签名集合 用英文逗号隔开 labelnames
    @Transactional(rollbackFor = { Exception.class })//事物控制
    @SysLog("更新问题")
    public ServerResponse<String> update(Map paramMap,HttpServletRequest request){
        int id = NumberUtil.safeToNumber(paramMap.get("id"));
        //查询问题基本信息
        Question question = questionMapper.selectByPrimaryKey(id);
        if(!LoginUtil.isLogin(request,question.getProposeUser())){
            //如果提问用户与登录用户不一致
            return ServerResponse.createByErrorMessage(Const.Msg.PARAMTERERROR);
        }
        if(null == question){
            return ServerResponse.createByErrorMessage(Const.Msg.PARAMTERERROR);
        }
        double money = NumberUtil.safeToDouble(paramMap.get("money"));
        int emergencyDegree = NumberUtil.safeToNumber(paramMap.get("emergency_degree"));
        if(emergencyDegree == Const.YesOrNo.YES && money < Const.MINMONEY){//如果是紧急并且小于100积分
            return ServerResponse.createByErrorMessage(Const.Msg.PARAMTERERROR);
        }
        int offered = NumberUtil.safeToNumber(paramMap.get("offered"));//是否悬赏
        //判断金额是否提高
        if(offered == Const.YesOrNo.YES){
            if(money > question.getMoney()){
                //继续扣款(当前数目 - 之前数目)
                double num = money - question.getMoney();
                if(num > 0){
                    ServerResponse response = iIntegralService.transaction(PropertiesUtil.getProperty("CapitalAccount"),
                            question.getProposeUser(),
                            num,Const.TradingNotes.ONE,Const.TradingNotes.ONE);
                    if (!response.isSuccess()){
                        throw new RuntimeException();
                    }
                }
            }
        }
        //查询大字段信息
        String content = questionBigFieldMapper.selectBigFileByQid(id);
        //保存历史记录
        if(addQuestionLog(question,content) != 2){
            return ServerResponse.createByErrorMessage(Const.Msg.SAVEERROR);
        }
        //保存基本信息
        question.setTitle(StringUtil.valueOfString(paramMap.get("title")));//标题
        question.setDescribe(StringUtil.valueOfString(paramMap.get("describe")));//问题描述
        question.setEmergencyDegree(NumberUtil.safeToNumber(paramMap.get("emergency_degree")));//紧急程度
        question.setMoney(money);//金额
        question.setAnswerNumber(NumberUtil.safeToNumber(paramMap.get("answer_number")));//回答数量
        question.setOffered(offered);//是否悬赏
        question.setAnswerModel(NumberUtil.safeToNumber(paramMap.get("answerModel")));//答案可见模式
        question.setAnswerMoney(NumberUtil.safeToDouble(paramMap.get("answerMoney")));//答案付费金额
        if(questionMapper.updateByPrimaryKeySelective(question) <= 0){
           throw new RuntimeException();
        }
        //更新solr内容信息
        iSolrService.del("joinid:"+question.getId()+" AND ENTITYNAME:"+Question.ENTITYNAME+
                " AND type:"+Const.SolrType.CONTENT);//删除索引
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id",UUID.randomUUID());
        doc.addField("joinid",question.getId());
        doc.addField("ENTITYNAME",Question.ENTITYNAME);//实体名称
        doc.addField("type",Const.SolrType.CONTENT);//实体类型
        doc.addField("title",question.getTitle());//标题
        doc.addField("bigfield",StringUtil.valueOfString(paramMap.get("content")));//大字段内容
        try {
            iSolrService.add(doc);//添加至solr服务器
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SolrServerException e) {
            e.printStackTrace();
        }
        //删除之前标签，新增现有标签
        String labels = StringUtil.valueOfString(paramMap.get("labels"));//标签集合
        if(StringUtil.isNotEmpty(labels)){
            //删除已有标签
            questionLabelMapper.delByQid(question.getId());
            //保存
            saveLabels(labels,question.getId());
        }
        return ServerResponse.createBySuccessMessage(Const.Msg.SAVESUCCESS);
    }

    /**
     * 添加问题修改记录
     * @param question
     * @return
     */
    @SysLog("添加问题修改记录")
    @Transactional(rollbackFor = { Exception.class })//事物控制
    public int addQuestionLog(Question question,String content){
        int countNum = 0;
        //添加历史
        QuestionLog questionLog = new QuestionLog();
        questionLog.setQid(question.getId());
        questionLog.setTitle(question.getTitle());
        questionLog.setDescribe(question.getDescribe());
        questionLog.setProposeUser(question.getProposeUser());
        questionLog.setEmergencyDegree(question.getEmergencyDegree());
        questionLog.setOffered(question.getOffered());
        questionLog.setMoney(question.getMoney());
        if(questionLogMapper.insert(questionLog) <= 0){
            throw new RuntimeException();
        }
        countNum++;
        //添加历史大字段信息
        LogQuestionBigField logb = new LogQuestionBigField();
        logb.setQid(questionLog.getId());
        logb.setBigtext(content);
        if(logQuestionBigFieldMapper.insert(logb) <= 0){
            throw new RuntimeException();
        }
        countNum++;
        return countNum;
    }

    /**
     * 删除提问（暂不打算提供删除功能）
     * @param id
     * @return
     */
    @SysLog("删除提问")
    public ServerResponse<String> delById(int id){
        return null;
    }

    /**
     * 保存问题集合标签
     * @param labels
     * @return
     */
    @SysLog("保存问题集合标签")
    public int saveLabels(String labels,int qid){
        int countNum = 0;
        if(StringUtil.isEmpty(labels)){
            return 0;
        }
        //保存现有标签
        String[] labelArr = labels.replaceAll("，",",").split(",");
        for (String label : labelArr){
            QuestionLabel questionLabel = new QuestionLabel();
            questionLabel.setQid(qid);
            questionLabel.setLid(NumberUtil.safeToNumber(label));
            if(questionLabelMapper.insert(questionLabel) <=0){
                throw new RuntimeException();
            }
            countNum++;
        }
        return countNum;
    }

    /**
     * 更新提问redis缓存
     */
    public void updateRedisCache(List<Map> mapList,Map paramMap,String keyName){
        mapList.add(paramMap);
        iJedisClientService.set(keyName,JSONObject.toJSONString(mapList));
        iJedisClientService.expire(keyName,Const.cacheTime*2);
    }


    /**
     * 根据ID查询问题详细信息
     * @param id
     * @return
     */
    @SysLog("查询问题详情")
    public ServerResponse<Map> selectById(Integer id,HttpServletRequest request){
        Map resultMap = questionMapper.selectById(id);
        Map paramMap = new HashMap();//统计查询条件
        paramMap.put("qid",id);
        String ip = ToolUtil.getClientIp(request);
        Object o = request.getSession().getAttribute(Const.CURRENT_USER);
        User user = null;
        if(o != null){
            paramMap.put("username",user.getUsername());
            user = (User)o;
        }else{
            paramMap.put("ip",ip);
        }
        if(null != resultMap){
            //浏览数
            resultMap.put("browseNums",questionBrowseRecordMapper.selectByQuestionId(id));
           // int answerModel = NumberUtil.safeToNumber(resultMap.get("answer_model"));
            resultMap.put("answerList",SearchBigFieldUtil.selectBigText(
                    answerMapper.selecyByQuestionId(id,Const.YesOrNo.YES),
                    Answer.ENTITYNAME,Const.SolrType.CONTENT,request));
            //todo 暂时不用考虑问题的答案查看模式
            /*if(answerModel == Const.AnswerModel.OPEN){//如果是答案公开
                //回答
                resultMap.put("answerList",answerList);
            }else{
                if(user != null){
                    paramMap.put("username",user.getUsername());
                    //查询是否有付费记录
                    if(questionPayRecordMapper.countQuestionIdAndUserName(id,user.getUsername()) > 0){
                        //回答
                        resultMap.put("answerList",answerList);
                    }
                }
            }*/
            //查询具体内容solr
            resultMap.put("content",SearchBigFieldUtil.searchContentById(id,Question.ENTITYNAME,
                    Const.SolrType.CONTENT));
            //查询用户/IP是否浏览过
            if(questionBrowseRecordMapper.countNumByParam(paramMap) <= 0){
                //添加浏览记录
                QuestionBrowseRecord questionBrowseRecord = new QuestionBrowseRecord();
                questionBrowseRecord.setQid(id);//提问ID
                questionBrowseRecord.setIp(ip);
                if(user != null){
                    questionBrowseRecord.setUsername(user.getUsername());
                }
                questionBrowseRecordMapper.insert(questionBrowseRecord);
            }

            return ServerResponse.createBySuccess(Const.Msg.SELECTSUCCESS,resultMap);
        }
        return ServerResponse.createByErrorMessage(Const.Msg.SELECTERROR);
    }


    /**
     * 查询付费答案
     * @param questionId 问题id
     * @param request
     * @return
     */
    @SysLog("查询付费答案")
    @Transactional(rollbackFor = { Exception.class })//事物控制
    public ServerResponse<List<Map>> selectQuestionAnswer(Integer questionId,HttpServletRequest request){
        Object o = request.getSession().getAttribute(Const.CURRENT_USER);
        if(o == null){
            return ServerResponse.createByErrorMessage(Const.Msg.USERNOLOGIN);
        }
        User user = (User)o;
        Question question = questionMapper.selectByPrimaryKey(questionId);
        if(question == null){
            return ServerResponse.createByErrorMessage(Const.Msg.PARAMTERERROR);
        }
        //用户积分交易
        //如果是悬赏的则进行交易操作
        ServerResponse response = iIntegralService.transaction(
                question.getProposeUser()/*进账方*/,user.getUsername()/*出帐方*/,
                question.getAnswerMoney()/*金额*/,
                Const.TradingNotes.FOUR/*进账备注*/,
                Const.TradingNotes.ONE/*出账备注*/);
        if (!response.isSuccess()){
            return response;
        }
        //添加问题答案付费记录
        QuestionPayRecord questionPayRecord = new QuestionPayRecord();
        questionPayRecord.setQuestionId(questionId);//提问ID
        questionPayRecord.setUsername(user.getUsername());//查看用户名
        questionPayRecord.setIp(ToolUtil.getClientIp(request));//Ip
        questionPayRecord.setMoney(question.getMoney());//金额
        if(questionPayRecordMapper.insert(questionPayRecord) == 0){
            throw new RuntimeException();
        }
        //查询答案
        return ServerResponse.createBySuccess(Const.Msg.SELECTSUCCESS,SearchBigFieldUtil.selectBigText(
                answerMapper.selecyByQuestionId(questionId,Const.YesOrNo.YES),
                Answer.ENTITYNAME,Const.SolrType.CONTENT,request));
    }

}
